/*
 * smart_main.c
 *
 *      Copyright 2009 Thadeu Ferreira de Melo <thadeu.afm@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 021MAXARG-1301, USA.
 *
 *  Created on: Mar 31, 2009
 *      Author: thadeumelo
 */




#include <stdlib.h>
#include <ncurses.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>

#include <string.h>

#define PROMPT "smart-shell->"
#define ARQHELP "help.txt"

#define MAXCHAR 256
#define MAXARG  10
#define MAXJOBS 5

extern char **environ;
extern int errno;
typedef void (*sighandler_t)(int);

static char *my_argv[MAXARG]; 	/*Vetor global de registro da linha de comando a ser executada*/

static char *paths[MAXARG]; 	/*Armazena os PATHs indexveis para a busca de execução*/
static char *my_envp[MAXCHAR];	/*variaveis de ambiente*/

static int jobid[MAXJOBS];
static int statusjob[MAXJOBS]; // 0 = running, 1 = stopped
static int controlejob = 0; // total number of jobs


int parser(char *cmd_lin){
	
	char *cmd_temp = cmd_lin;
	int index = 0;
	int opt = 0;
	char arg[MAXARG];

	bzero(arg, MAXARG);

	while(*cmd_temp != '\0') {
		if(index == MAXARG)
			break;

			/*Passa a considerar palavras entre "aspas" 
				como um unico argumento*/
			if(*cmd_temp == '\"')
				do{
					strncat(arg, cmd_temp, 1);
					cmd_temp++;
				}while(*cmd_temp != '\"');
	
			if((*cmd_temp == ' ')&& (*cmd_temp != '\0')){
	
				if(my_argv[index] == NULL)
					my_argv[index] = (char *)malloc(sizeof(char) * strlen(arg) + 1);
				else {
					bzero(my_argv[index], strlen(my_argv[index]));
				}
				strncpy(my_argv[index], arg, strlen(arg));
				strncat(my_argv[index], "\0", 1);
				bzero(arg, MAXARG);
				index++;
			} else {
				strncat(arg, cmd_temp, 1);
			}
		cmd_temp++;
	}

		my_argv[index] = (char *)malloc(sizeof(char) * strlen(arg) + 1);
		strncpy(my_argv[index], arg, strlen(arg));
		strncat(my_argv[index], "\0", 1);


	return index;
}

void cm_help() {
        FILE* arq_help;
        char* lido;
        arq_help = fopen(ARQHELP, "r");
        while(fgets(lido, sizeof(lido), arq_help)) {
                printf("%s", lido);
        }

        fclose(arq_help);

}

void cm_exit(){
	int i;
	//printf("QUER SAIR\n");
	for(i=0;i <= controlejob;i++)
		 kill(jobid[i],SIGKILL);
	fflush(stdout);
	refresh();                      /* Print it on to the real screen */
        endwin();                       /* End curses mode                 */
	exit(EXIT_SUCCESS);
}

int call_exec(char *cmd){

	int i;
	/* Execusão de funções internas*/
	if (strcmp(cmd, "exit") == 0){

                        cm_exit();
                }
	if (strcmp(cmd, "help") == 0){
			cm_help();
                }

	if(fork() == 0) {
		i = execve(cmd, my_argv, my_envp);
		printf("errno is %d\n", errno);
		if(i < 0) {
			printf("%s: %s\n", cmd, "command not found");
			exit(1);		
		}
	} else {
		wait(NULL);
	}


}

/**
 * Copia as variaveis de ambiente
 *
 * @author Thadeu Melo
 * @param char** varialve de ambiente
 * @return void
 */
void copy_envp(char **envp)
{
	int index = 0;
	for(;envp[index] != NULL; index++) {
		my_envp[index] = (char *)malloc(sizeof(char) * (strlen(envp[index]) + 1));
		memcpy(my_envp[index], envp[index], strlen(envp[index]));
	}
}

/**
 * Faz um parser dos diferentes PATHs indexveis 
 * colocando no  vetor global paths[]
 *
 * @author Thadeu Melo
 * @param char* varialve de ambiente
 * @return void
 */
void search_paths(char *path_str) 
{
	int index=0;
	char *tmp = path_str;
	char ret[MAXCHAR];

	while(*tmp != '=')
		tmp++;
	tmp++;

	while(*tmp != '\0') {
		if(*tmp == ':') {
			strncat(ret, "/", 1);
			paths[index] = (char *) malloc(sizeof(char) * (strlen(ret) + 1));
			strncat(paths[index], ret, strlen(ret));
			strncat(paths[index], "\0", 1);
			index++;
			bzero(ret, MAXCHAR);
		} else {
			strncat(ret, tmp, 1);
		}
		tmp++;
	}
}

/**
 * Carrega a variavel de ambiante como um parametro
 * e le o valor do PATH por inteiro 
 *
 * @author Thadeu Melo
 * @param char** variavel de ambiente
 * @param char* path inicial
 * @return void
 */
void get_path_string(char **tmp_envp, char *bin_path)
{
	int count = 0;
	char *tmp;
	while(1) {
		tmp = strstr(tmp_envp[count], "PATH"); /*pega o ponteiro para o principio da string*/
		if(tmp == NULL) {
			count++;
		} else {
			break;
		}
	}
        strncpy(bin_path, tmp, strlen(tmp));
}

/**
 * Verifica a existencia de um comando no PATH
 *
 * @author Thadeu Melo
 * @param char* Comando a ser procurado
 * @return int 0 caso o comando tenha sido encontrado
 */
int attach_path(char *cmd){
	
	char ret[MAXCHAR];
	int i;
	int fd;
	bzero(ret, MAXCHAR);

	for(i=0 ; paths[i] != NULL ; i++) {
		strcpy(ret, paths[i]);
		strncat(ret, cmd, strlen(cmd));
		if((fd = open(ret, O_RDONLY)) > 0) {
			strncpy(cmd, ret, strlen(ret));
			close(fd);
			return 0;
		}
	}
	return 0;
}

void handle_signal(int signo){
	cm_exit();
}



/**
 * Limpa o vetor de argumentos
 *
 * @author Thadeu Melo
 * @param 
 * @return void
 */
void free_argv()
{
	int index;
	for(index=0;my_argv[index]!=NULL;index++) {
		bzero(my_argv[index], strlen(my_argv[index])+1);
		my_argv[index] = NULL;
		free(my_argv[index]);
	}
}



int main(int argc, char *argv[], char *envp[])
{
	char ch, temp_ch;
	int i, fd, args;
	int linha = 0;
	int coluna = 0;
	char *lin_cmd = (char *)malloc(sizeof(char) * MAXCHAR);
	char *dir_str = (char *)malloc(sizeof(char) * MAXCHAR); /*Diretorio atual*/
	char *path_str = (char *)malloc(sizeof(char) * MAXCHAR);
	char *cmd = (char *)malloc(sizeof(char) * MAXCHAR);

	/*condicao padrão da saida e entrada*/
	/*indicadores de entradas e saidas padroes*/
	char *saida = (char *)malloc(sizeof(char) * MAXCHAR);
	char *entrada = (char *)malloc(sizeof(char) * MAXCHAR);

	signal(SIGINT, SIG_IGN);
	signal(SIGINT, handle_signal);
	getcwd(dir_str, MAXCHAR);


        copy_envp(envp);
        get_path_string(my_envp, path_str);


	initscr();            /* Start curses mode            */

	clear();
	keypad(stdscr, TRUE); /* We get F1, F2 etc..          */
	noecho();             /* Don't echo() while we do getch */

	mvprintw(linha,coluna,"%s %s$", PROMPT, dir_str);
	
	while(TRUE) {
		ch = getch();

	switch(ch){
		case '\n': 	if(lin_cmd[0] == '\0') {
					
					mvprintw(++linha,coluna,"%s %s$", PROMPT, dir_str);
					/*LINHA VASIA*/
				}
				else{
					/*salva comando na lista de comandos
						(NÃO IMPLEMENTADO)*/

					/* parse and execute. */
					parser(lin_cmd);
					strncpy(cmd, my_argv[0], strlen(my_argv[0])); /*Copia o primeiro argumentos como 
												comando a ser executado*/
					strncat(cmd, "\0", 1);
					/* A funçao attach_path será chamada caso o parametro cmd (comando) nao possuir um caracter '/'.
					Quando o comando tem um '/', o usuario está especificando um caminho (path)*/
					if(index(cmd, '/') == NULL) {
							if(attach_path(cmd) == 0) {
								call_exec(cmd);
							} else {
								printf("%s: command not found\n", cmd);
							}
						} else {
							if((fd = open(cmd, O_RDONLY)) > 0) {
								close(fd);
								call_exec(cmd);
							} else {
								printf("%s: command not found\n", cmd);
							}
						}
					mvprintw(++linha,coluna,"%s %s$", PROMPT, dir_str);
					bzero(cmd, MAXCHAR); /*limpa os comandos executados*/
					free_argv(); /*limpa vetor de argumentos*/
					bzero(lin_cmd, sizeof(lin_cmd)); 	//Limpa a linha de comando
					
					/*Redefinindo para condicao padrão 
						da saida e entrada*/
					saida = NULL;
					entrada = NULL;
				}
				
			break;
		case 02:	printw("\nSETA PARA BAIXO$\n");
				/*Percorre a lista de linhas de comando*/
			break;
		case 03:	printw("\nSETA PARA CIMA$\n");
				/*Percorre a lista de linhas de comando*/
			break;
		case 04:	printw("\nSETA PARA ESQUERDA$\n");
			break;
		case 05:	printw("\nSETA PARA DIREITA$\n");
			break;
		case 011:	printw("\nTAB PRECIONADO$\n");
			break;
		default: 	printw("%c",ch);
				if ( !((temp_ch == ' ')&&(ch == ' '))) /*Desconsidera espaços digitados repetidamente*/
				strncat(lin_cmd,&ch,1);
				temp_ch = ch;
				break;
		}

	}

	return 0;
}


